﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Internal.KuiHuaBaoDian.Services.Guide;
using Newtonsoft.Json;
using KuiHuaBaoDian.Services.Guide;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace KuiHuaBaoDian.Services.Guide {

    public interface IGuideSection {

        int ID { get; }

        string Name { get; }

        bool IsDone { get; }

        IReadOnlyList<GuideReference> GetVariable(string key);
    }

    [JsonObject(MemberSerialization.OptIn)]
    public sealed class GuideSection : ScriptableObject, IGuideSection, IGuideSectionInternal {

        void IGuideSectionInternal.SetDataFrom(IGuideSection another) {
            if (another.IsDone) {
                Done();
            }
        }

        private class TriggerRecord {

            public GuideTrigger Entity;

            public bool State;
        }

        private readonly Dictionary<IGuideTriggerKey, TriggerRecord> m_TriggerDictionary = new();

        private readonly Dictionary<IGuideTriggerKey, TriggerRecord> m_StateDictionary = new();

        private readonly List<GuideTrigger> m_ValidateList = new();

        [SerializeField]
        private int m_ID;

        [JsonProperty("id")]
        public int ID => m_ID;

        [JsonProperty("state")]
        public int State => IsDone ? 1 : 0;

        [Space]
        [SerializeField]
        private List<GuideEntity> m_EntityList = new();
        public IReadOnlyList<GuideEntity> EntityList => m_EntityList;

        private Dictionary<string, IReadOnlyList<GuideReference>> m_VariableDictionary = new();

        public string Name => name;

        public bool IsDone { get; private set; }

        private IReadOnlyDictionary<Guid, GuideEntity> m_EntityDictionary;

        public void Initialize() {
            var dictionary = new Dictionary<Guid, GuideEntity>();
            foreach (var serializedEntity in m_EntityList) {
                var entity = UnityEngine.Object.Instantiate(serializedEntity);
                dictionary[entity.GUID] = entity;
                if (entity is GuideTrigger triggerEntity) {
                    switch (triggerEntity.Type) {
                        case GuideTriggerType.Trigger:
                            m_TriggerDictionary[triggerEntity.Key] = new TriggerRecord { Entity = triggerEntity };
                            break;
                        case GuideTriggerType.State:
                            m_StateDictionary[triggerEntity.Key] = new TriggerRecord { Entity = triggerEntity };
                            break;
                        case GuideTriggerType.Validate:
                            m_ValidateList.Add(triggerEntity);
                            break;
                        default:
                            throw new NotSupportedException();
                    }
                }
            }
            m_EntityDictionary = dictionary;
            name = name[..^7];
        }

        public GuideEntity StartEntity => m_EntityDictionary.Where(kv => kv.Value is GuideStart).Select(kv => kv.Value).FirstOrDefault();

        public IEnumerable<GuideTrigger> TriggerEntities {
            get {
                if (m_EntityDictionary.Count > 2) {
                    var isValid = false;
                    var nextIsLogic = false;
                    var parentEntity = StartEntity;
                    while (parentEntity != null && parentEntity.OutputTo != Guid.Empty && m_EntityDictionary.TryGetValue(parentEntity.OutputTo, out var entity)) {
                        if (entity is GuideTriggerAnd) {
                            if (nextIsLogic) {
                                nextIsLogic = false;
                            } else {
                                Debug.LogError($"引导触发器逻辑错误, [节选({name})]");
                                break;
                            }
                        } else if (entity is GuideTrigger triggerEntity && !nextIsLogic) {
                            if (!nextIsLogic) {
                                yield return triggerEntity;
                                nextIsLogic = true;
                            } else {
                                Debug.LogError($"引导触发器逻辑错误, [节选({name})]");
                                break;
                            }
                        } else if (entity is GuideTriggerEnd) {
                            isValid = true;
                        }
                        parentEntity = entity;
                    }
                    if (!isValid) {
                        Debug.LogError($"当前引导触发器数据非法, [节选({name})]");
                    }
                }
            }
        }

        public void Done() {
            if (!IsDone) {
                IsDone = true;
                m_VariableDictionary = null;
            }
        }

        public void Failure() {
            if (IsDone) {
                IsDone = false;
                foreach (var kv in m_TriggerDictionary) {
                    kv.Value.State = false;
                }
                foreach (var kv in m_StateDictionary) {
                    kv.Value.State = false;
                }
                m_VariableDictionary = new();
            }
        }

        public bool Trigger(IGuideTriggerKey key) {
            if (m_TriggerDictionary.TryGetValue(key, out var triggerRecord)) {
                triggerRecord.State = triggerRecord.Entity.Validate();
            }
            if (m_StateDictionary.TryGetValue(key, out var stateRecord)) {
                stateRecord.State = true;
            }
            var result = true;
            foreach (var kv in m_TriggerDictionary) {
                if (!kv.Value.State) {
                    result = false;
                    break;
                }
            }
            if (result) {
                foreach (var kv in m_StateDictionary) {
                    if (!kv.Value.State) {
                        result = false;
                        break;
                    }
                }
            }
            if (result) {
                foreach (var entity in m_ValidateList) {
                    if (!entity.Validate()) {
                        result = false;
                        break;
                    }
                }
            }
            return result;
        }

        public void Recovery(IGuideTriggerKey key) {
            if (m_StateDictionary.TryGetValue(key, out var record)) {
                record.State = false;
            }
            foreach (var kv in m_TriggerDictionary) {
                kv.Value.State = false;
            }
        }

        public IEnumerable<IGuideStep> Steps {
            get {
                var parentEntity = StartEntity;
                while (parentEntity != null && m_EntityDictionary.TryGetValue(parentEntity.NextTo, out var entity)) {
                    if (entity is IGuideStepInternal step) {
                        yield return step;
                        while (m_EntityDictionary.TryGetValue(step.OutputTo, out var outputTo) && outputTo is IGuideStepInternal outputStep) {
                            yield return outputStep;
                            step = outputStep;
                        }
                    } else {
                        Debug.LogError($"引导步骤错误, [节选({name})]");
                        break;
                    }
                    parentEntity = entity;
                }
            }
        }

        public IReadOnlyList<GuideReference> GetVariable(string key) => m_VariableDictionary[key];

        public void SetVariable(string key, IReadOnlyList<GuideReference> referenceList) => m_VariableDictionary[key] = referenceList;

#if UNITY_EDITOR
        public GuideEntity AddEntity(Type type) {
            var entity = CreateInstance(type) as GuideEntity;
            entity.name = type.Name;
            entity.GUID = Guid.NewGuid();
            m_EntityList.Add(entity);

            AssetDatabase.AddObjectToAsset(entity, this);
            AssetDatabase.SaveAssets();
            return entity;
        }

        public void RemoveEntity(GuideEntity entity) {
            m_EntityList.Remove(entity);
            AssetDatabase.RemoveObjectFromAsset(entity);
            AssetDatabase.SaveAssets();
        }

        public void ClearMissingEntities() {
            var so = new SerializedObject(this);
            var sp = so.FindProperty(nameof(m_EntityList));
            for (var i = 0; i < sp.arraySize; ++i) {
                var item = sp.GetArrayElementAtIndex(i);
                if (item.objectReferenceValue is GuideEntity entity) {
                    if (entity.GUID == Guid.Empty) {
                        sp.DeleteArrayElementAtIndex(i--);
                    }
                } else {
                    sp.DeleteArrayElementAtIndex(i--);
                }
            }
            so.ApplyModifiedPropertiesWithoutUndo();
            var assets = AssetDatabase.LoadAllAssetRepresentationsAtPath(AssetDatabase.GetAssetPath(this));
            var isDirty = false;
            foreach (var asset in assets) {
                if (asset is GuideEntity entity) {
                    if (entity.GUID == Guid.Empty || !m_EntityList.Contains(entity)) {
                        AssetDatabase.RemoveObjectFromAsset(entity);
                        isDirty = true;
                    }
                } else if (asset == null) {
                    UnityEngine.Object.DestroyImmediate(asset);
                    isDirty = true;
                } else {
                    AssetDatabase.RemoveObjectFromAsset(asset);
                    isDirty = true;
                }
            }
            if (isDirty) {
                AssetDatabase.SaveAssets();
            }
        }
#endif
    }
}

namespace Internal.KuiHuaBaoDian.Services.Guide {

    public interface IGuideSectionInternal {

        void SetDataFrom(IGuideSection another);

        void Done();

        void Failure();
    }
}
